// LexicalRule.cs created with MonoDevelop
// User: luis at 20:20 28/04/2008
//
// To change standard headers go to Edit->Preferences->Coding->Standard Headers
//

using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;

namespace MathTextLibrary.Analisys
{
	
	/// <summary>
	/// This class implements the lexicals rules used to match symbols sequences
	/// into tokens.
	/// </summary>
	public class LexicalRule
	{
		private List<string> lexicalExpressions;
		private string ruleName;
		
		private List<Regex> regularExpressions;
		
		
		/// <summary>
		/// <c>LexicalRule</c>'s connection.
		/// </summary>
		public LexicalRule()
		{
			lexicalExpressions = new List<string>();
			regularExpressions = null;
		}
		
#region Properties
		
		/// <value>
		/// Contains the regular expressions used to perform the lexical
		/// matching for this rule.
		/// </value>
		public List<string> LexicalExpressions 
		{
			get 
			{
				return lexicalExpressions;
			}
			set 
			{
				lexicalExpressions = value;
				
				// We clear the expressions list so we have to create one.
				regularExpressions = null;
			}
		}

		/// <value>
		/// Contains the rule's name, wich will be used as the type of the 
		/// tokens generated by this rule.
		/// </value>
		public string Name 
		{
			get 
			{
				return ruleName;
			}
			set 
			{
				ruleName = value;
			}
		}
		
#endregion Properties
		
#region Public methods
		
		/// <summary>
		/// Tries to match a given token sequence with this rule.
		/// </summary>
		/// <param name="tokens">
		/// The tokens we try to group.
		/// </param>		
		/// <param name="foundToken">
		/// The token result of joining the sequence, has a meaning or not.
		/// </param>
		/// <returns>
		/// If a valid token was found.
		/// </returns>
		public bool Match(TokenSequence tokens, out Token foundToken)
		{
			// We form the expression to be matched.
			string text = "";
			foreach(Token t in tokens)
			{
				if(!String.IsNullOrEmpty(t.Type))
				{
					text += String.Format("%%{0}%%", t.Type);
				}
				else
				{
					text += t.Text;
				}
			}
			
			if(regularExpressions == null)
			{				
				// We have to load the expressions.
				regularExpressions = new List<Regex>();
				foreach(string pattern in lexicalExpressions)
				{
					// We add the modifiers to apply the regex to all the 
					// text.
					Regex regex = new Regex(String.Format("^{0}$",pattern),
					                        RegexOptions.Compiled 
					                        |RegexOptions.Singleline);
					
					regularExpressions.Add(regex);
				}
			}
			
			bool found = false;
			
			// Now we try to match a rule with the text.
			foreach(Regex expression in regularExpressions)
			{
				Match match = expression.Match(text);
				if(match.Success)
				{
					found = true;
					break;
				}
			}			
			
			foundToken = Token.Join(tokens, this.ruleName);
			
			return found;
		}
		
		
#endregion Public methods
	}
}
